import pika
import json
import logging
from typing import Any, Dict, Callable
from app.core.config import settings

logger = logging.getLogger(__name__)

class RabbitMQClient:
    """RabbitMQ客户端，处理消息发送和接收"""
    
    def __init__(self):
        """初始化RabbitMQ连接"""
        self.connection = None
        self.channel = None
        self.connect()
    
    def connect(self):
        """连接到RabbitMQ服务器"""
        try:
            credentials = pika.PlainCredentials(
                settings.RABBITMQ_USER, 
                settings.RABBITMQ_PASSWORD
            )
            
            parameters = pika.ConnectionParameters(
                host=settings.RABBITMQ_HOST,
                port=settings.RABBITMQ_PORT,
                virtual_host='/',
                credentials=credentials
            )
            
            self.connection = pika.BlockingConnection(parameters)
            self.channel = self.connection.channel()
            
            # 声明交换机
            self.channel.exchange_declare(
                exchange='lvyou',
                exchange_type='topic',
                durable=True
            )
            
            # 声明常用队列
            self.declare_queue('chat_messages')
            self.declare_queue('notifications')
            self.declare_queue('campsite_updates')
            
            logger.info("Connected to RabbitMQ")
        except Exception as e:
            logger.error(f"Failed to connect to RabbitMQ: {e}")
            self.connection = None
            self.channel = None
    
    def declare_queue(self, queue_name: str):
        """声明队列"""
        if self.channel:
            self.channel.queue_declare(
                queue=queue_name,
                durable=True
            )
            
            # 将队列绑定到交换机
            self.channel.queue_bind(
                exchange='lvyou',
                queue=queue_name,
                routing_key=queue_name
            )
    
    def publish_message(self, routing_key: str, message: Dict[str, Any]):
        """发布消息到RabbitMQ"""
        if not self.channel:
            self.connect()
            if not self.channel:
                logger.error("Cannot publish message: not connected to RabbitMQ")
                return False
        
        try:
            self.channel.basic_publish(
                exchange='lvyou',
                routing_key=routing_key,
                body=json.dumps(message),
                properties=pika.BasicProperties(
                    delivery_mode=2,  # 持久化消息
                    content_type='application/json'
                )
            )
            return True
        except Exception as e:
            logger.error(f"Failed to publish message: {e}")
            # 尝试重新连接
            self.connect()
            return False
    
    def consume_messages(self, queue_name: str, callback: Callable):
        """消费消息"""
        if not self.channel:
            self.connect()
            if not self.channel:
                logger.error("Cannot consume messages: not connected to RabbitMQ")
                return
        
        try:
            self.channel.basic_consume(
                queue=queue_name,
                on_message_callback=callback,
                auto_ack=False
            )
            
            logger.info(f"Started consuming messages from {queue_name}")
            self.channel.start_consuming()
        except Exception as e:
            logger.error(f"Failed to consume messages: {e}")
            # 尝试重新连接
            self.connect()
    
    def close(self):
        """关闭连接"""
        if self.connection:
            self.connection.close()
            self.connection = None
            self.channel = None
            logger.info("Closed RabbitMQ connection")

# 创建RabbitMQ客户端单例
rabbitmq_client = RabbitMQClient()

# 消息类型
class MessageType:
    """消息类型枚举"""
    CHAT_MESSAGE = "chat_messages"
    NOTIFICATION = "notifications"
    CAMPSITE_UPDATE = "campsite_updates"

def publish_chat_message(message_data: Dict[str, Any]) -> bool:
    """发布聊天消息"""
    return rabbitmq_client.publish_message(MessageType.CHAT_MESSAGE, message_data)

def publish_notification(notification_data: Dict[str, Any]) -> bool:
    """发布通知消息"""
    return rabbitmq_client.publish_message(MessageType.NOTIFICATION, notification_data)

def publish_campsite_update(update_data: Dict[str, Any]) -> bool:
    """发布营地更新消息"""
    return rabbitmq_client.publish_message(MessageType.CAMPSITE_UPDATE, update_data) 